package com.jsbs.iam.auth.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jsbs.iam.auth.constant.RedisConstants;
import com.jsbs.iam.auth.dto.*;
import com.jsbs.iam.auth.feign.IamRoleManagerFeign;
import com.jsbs.iam.auth.mapper.*;
import com.jsbs.iam.auth.param.IamQueryStaticUserGroupParam;
import com.jsbs.iam.auth.param.IamQueryStaticUserGroupUsersParam;
import com.jsbs.iam.auth.param.IamRoleQueryUserParam;
import com.jsbs.iam.auth.param.IamStaticUserGroupDeleteParam;
import com.jsbs.iam.auth.service.IamStaticUserGroupManagerService;
import com.jsbs.iam.auth.vo.IamUserGroupVo;
import com.jsbs.iam.auth.vo.IamUserInfoVo;
import com.jsbs.iam.auth.vo.MenuThreeVo;
import com.jsbs.iam.common.core.dto.Result;
import com.jsbs.iam.common.core.utils.Json;
import com.jsbs.iam.common.core.utils.PageHelperTool;
import com.jsbs.iam.common.core.utils.StringUtils;
import com.jsbs.iam.common.redis.service.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @ClassName: UserGroupManagerServiceImpl
 * @Author: tenghuawei
 * @Date: 2023/1/5 15:29
 * @Description:
 */

@Slf4j
@Service
public class IamStaticUserGroupManagerServiceImpl implements IamStaticUserGroupManagerService {

    @Resource
    private RedissonClient redissonClient;

    @Autowired
    IamStaticUserGroupManagerMapper iamStaticUserGroupManagerMapper;

    @Autowired
    IamRoleManagerFeign iamRoleManagerFeign;

    @Autowired
    IamDynamicUserGroupManagerMapper iamDynamicUserGroupManagerMapper;

    @Autowired
    IamUserGroupMenuRelationMapper iamUserGroupMenuRelationMapper;

    @Autowired
    IamUserGroupButtonRelationMapper iamUserGroupButtonRelationMapper;

    @Autowired
    IamUserGroupUserRelationMapper iamUserGroupUserRelationMapper;

    @Autowired
    IamUserGroupDynamicFilterRuleMapper iamUserGroupDynamicFilterRuleMapper;

    @Value("${_env.name}")
    private String envName;

    /**
     * 功能描述：新增静态用户组
     * @param iamStaticUserGroupAddDto
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int createStaticUserGroup(IamStaticUserGroupAddDto iamStaticUserGroupAddDto) {
        // 新建角色生成角色编码时加锁，失效时间10秒钟
        RLock lock = redissonClient.getLock(RedisConstants.AUTH_STATIC_USER_GROUP_CODE_LOCK);
        Long staticUserGroupCode = null;
        try {
            // 5分钟内重试获取锁，10秒后释放
            boolean isLocked = lock.tryLock(5 * 60 * 1000L, 10 * 1000L, TimeUnit.MILLISECONDS);
            // 获取到锁后，进行自增
            if (!isLocked) {
                log.warn("Route=>UserGroupManagerServiceImpl method=>createStaticUserGroup  新建静态用户组获取不到锁，生成用户组编码失败，入参为:{}", Json.toJsonString(iamStaticUserGroupAddDto));
                throw new RuntimeException("获取STATIC_USER_GROUP_CODE_LOCK锁失败！");
            }
            // 加锁成功后,获取当前缓存值
            String value = RedisUtils.get(envName + RedisConstants.AUTH_STATIC_USER_GROUP_CODE);
            // 若为空则从数据库取当前最大值+1
            if (StringUtils.isEmpty(value)) {
                staticUserGroupCode = Long.valueOf(iamStaticUserGroupManagerMapper.getMaxStaticUserGroupCode()) + 1;
            } else {
                // 当前缓存获取成功，并加新增用户数量入缓存
                staticUserGroupCode = Long.parseLong(value) + 1;
            }
            // 将最新值更新到缓存中
            RedisUtils.set(envName + RedisConstants.AUTH_STATIC_USER_GROUP_CODE, String.valueOf(staticUserGroupCode));
        } catch (Exception e) {
            log.error("Route=>UserGroupManagerServiceImpl method=>createStaticUserGroup 新建静态用户组异常:{}, 入参为:{}", e.getMessage(),Json.toJsonString(iamStaticUserGroupAddDto));
            throw new RuntimeException("新建静态用户组异常!");
        } finally {
            // 手动解锁
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
        AtomicReference<Long> finalCode = new AtomicReference<>(staticUserGroupCode);
        iamStaticUserGroupAddDto.setUserGroupCode("JT" + String.format("%06d", finalCode.getAndSet(finalCode.get())));
        log.info("Route=>UserGroupManagerServiceImpl method=>createStaticUserGroup  新建静态用户组 生成用户组编码成功:{}", finalCode.get());
        //新增静态用户组时，校验用户组名的唯一性
        int count = iamDynamicUserGroupManagerMapper.checkDynamicUserGroupName(iamStaticUserGroupAddDto.getUserGroupName(),
                iamStaticUserGroupAddDto.getCompanyCode());
        if(count>0){
            throw new RuntimeException("新增静态用户组时，该用户组名已存在！");
        }
        return iamStaticUserGroupManagerMapper.createStaticUserGroup(iamStaticUserGroupAddDto);
    }

    /**
     * 功能描述：查询静态态用户组
     * @param iamQueryStaticUserGroupParam
     * @return PageInfo
     */
    @Override
    public PageInfo<IamUserGroupVo> queryUserGroup(IamQueryStaticUserGroupParam iamQueryStaticUserGroupParam) {
        iamQueryStaticUserGroupParam.init();
        PageHelper.startPage(iamQueryStaticUserGroupParam.getCurrPage(),iamQueryStaticUserGroupParam.getPageSize());
        List<IamUserGroupVo> iamUserGroupVos = iamStaticUserGroupManagerMapper.queryUserGroup(iamQueryStaticUserGroupParam);
        PageInfo<IamUserGroupVo> initPageInfo = new PageInfo<>(iamUserGroupVos);
        PageInfo<IamUserGroupVo> pageInfo = PageHelperTool.initPageInfoObj(iamQueryStaticUserGroupParam.getCurrPage(), (int) initPageInfo.getTotal(),
                iamQueryStaticUserGroupParam.getPageSize(), initPageInfo);
        return pageInfo;
    }

    /**
     * 功能描述：编辑静态用户组
     * @param iamStaticUserGroupEditDto
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int userGroupEdit(IamStaticUserGroupEditDto iamStaticUserGroupEditDto) {
        //编辑时，如果修改了用户组名，需要校验其唯一性
        String userGroupName = iamDynamicUserGroupManagerMapper.queryDynamicUserGroupName(iamStaticUserGroupEditDto.getCompanyCode(),
                iamStaticUserGroupEditDto.getUserGroupCode(),iamStaticUserGroupEditDto.getAdminRoleCode());
        if(StringUtils.equalsIgnoreCase(userGroupName,iamStaticUserGroupEditDto.getUserGroupName())){
            log.info("Route=>DynamicUserGroupManagerServiceImpl method=>userGroupEdit  编辑静态用户组时没有修改用户组名");
        }else {
            //校验用户组名的唯一性
            int count = iamDynamicUserGroupManagerMapper.checkDynamicUserGroupName(iamStaticUserGroupEditDto.getUserGroupName(),
                    iamStaticUserGroupEditDto.getCompanyCode());
            if(count>0){
                throw new RuntimeException("该用户组名已存在，请重新编辑用户组名！");
            }
        }
        return iamStaticUserGroupManagerMapper.userGroupEdit(iamStaticUserGroupEditDto);
    }

    /**
     * 功能描述：删除动、静态用户组
     * @param iamStaticUserGroupDeleteParam
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userGroupDelete(IamStaticUserGroupDeleteParam iamStaticUserGroupDeleteParam) {
        // 删除该用户组关联的所有用户
        if(iamUserGroupUserRelationMapper.deleteUserGroupUserRelation(iamStaticUserGroupDeleteParam)){
            throw new RuntimeException("删除该用户组关联的所有用户失败！");
        }
        // 删除该用户组关联的菜单或按钮
        IamStaticUserGroupUsersPermissionEditingDto deleteMenuAndButton = new IamStaticUserGroupUsersPermissionEditingDto();
        BeanUtils.copyProperties(iamStaticUserGroupDeleteParam,deleteMenuAndButton);
        // ① 删除关联菜单
        int deleteMenu=iamUserGroupButtonRelationMapper.deleteUserGroupButtonRelation(deleteMenuAndButton);
//        if(0==deleteMenu){
//            throw new RuntimeException("删除该用户组所关联的菜单失败！");
//        }
        // ② 删除关联按钮
        int deleteButton=iamUserGroupButtonRelationMapper.deleteUserGroupButtonRelation(deleteMenuAndButton);
//        if(0==deleteButton){
//            throw new RuntimeException("删除该用户组所关联的按钮失败！");
//        }
        // 如果是动态用户组，还需要删除动态用户组规则表中的该动态用户组的数据
        if(iamStaticUserGroupDeleteParam.getUserGroupCode().trim().startsWith("DT")){
            int deleteUserGroupDynamicFilterRule = iamUserGroupDynamicFilterRuleMapper.
                    userGroupDynamicFilterRuleADelete(iamStaticUserGroupDeleteParam);
//            if(0==deleteUserGroupDynamicFilterRule){
//                throw new RuntimeException("动态用户组的规则表数据删除失败！");
//            }
        }
        // 删除动/静态用户组
        int userGroupDelete = iamStaticUserGroupManagerMapper.userGroupDelete(iamStaticUserGroupDeleteParam);
        if(0==userGroupDelete){
            throw new RuntimeException("删除该用户组失败！");
        }
    }

    /**
     * 功能描述：选择一个静态用户组，查询用户（该静态用户组下的用户，分页展示）
     * @param iamQueryStaticUserGroupUsersParam
     * @return List
     */
    @Override
    public PageInfo<IamUserInfoVo> queryUserGroupUsers(IamQueryStaticUserGroupUsersParam iamQueryStaticUserGroupUsersParam) {
        //查询某个静态用户组下的用户id集合
        List<String> userCodes = iamStaticUserGroupManagerMapper.queryUserGroupUsers(iamQueryStaticUserGroupUsersParam);
        if(CollectionUtils.isEmpty(userCodes)){
            throw new RuntimeException("该静态用户组下未查询任何用户信息,请更换查询条件！");
        }
        IamRoleQueryUserParam iamRoleQueryUserParam = new IamRoleQueryUserParam();
        //封装feign调用的参数
        BeanUtils.copyProperties(iamQueryStaticUserGroupUsersParam,iamRoleQueryUserParam);
        iamRoleQueryUserParam.setUserCodes(userCodes);
        Result<PageInfo<IamUserInfoVo>> pageInfoResult = iamRoleManagerFeign.queryRoleBindUsers(iamRoleQueryUserParam);
        PageInfo<IamUserInfoVo> pageInfo = pageInfoResult.getData();
        return pageInfo;
    }


    /**
     * 功能描述：某个静态用户组下可以新增的用户（分页展示）
     * @param
     * @return PageInfo<IamUserInfoVo>
     */
    @Override
    public  PageInfo<IamUserInfoVo> queryUserGroupNotUsers(IamQueryStaticUserGroupUsersParam iamQueryStaticUserGroupUsersParam) {
        //查询某个静态用户组下的用户id集合
        List<String> userCodes = iamStaticUserGroupManagerMapper.queryUserGroupUsers(iamQueryStaticUserGroupUsersParam);
        IamRoleQueryUserParam iamRoleQueryUserParam = new IamRoleQueryUserParam();
        //封装feign调用的参数
        BeanUtils.copyProperties(iamQueryStaticUserGroupUsersParam,iamRoleQueryUserParam);
        iamRoleQueryUserParam.setUserCodes(userCodes);
        Result<PageInfo<IamUserInfoVo>> result = iamRoleManagerFeign.queryRoleNotBindUsers(iamRoleQueryUserParam);
        if(Objects.isNull(result.getData())){
            throw  new RuntimeException("未找到相关数据，建议您更换筛选条件!");
        }
        PageInfo<IamUserInfoVo> pageInfo = result.getData();
        return pageInfo;
    }

    /**
     * 功能描述：某个静态用户组下新增用户
     * @param iamStaticUserGroupUsersAddDto
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userGroupUserAdd(IamStaticUserGroupUsersAddDto iamStaticUserGroupUsersAddDto) {
        int userAdd = iamStaticUserGroupManagerMapper.userGroupUserAdd(iamStaticUserGroupUsersAddDto);
        if(0==userAdd){
            throw  new RuntimeException("该静态用户组下新增用户失败！");
        }
    }

    /**
     * 功能描述：某个静态用户组下移除用户
     * @param iamStaticUserGroupUsersRemoveDto
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int userGroupUsersRemove(IamStaticUserGroupUsersRemoveDto iamStaticUserGroupUsersRemoveDto) {
        int usersRemove = iamStaticUserGroupManagerMapper.userGroupUsersRemove(iamStaticUserGroupUsersRemoveDto);
        if(0==usersRemove){
            throw new RuntimeException("静态用户组下移除用户失败！");
        }
        return usersRemove;
    }

    /**
     * 功能描述：查询当前普管用户的1个应用类型下的权限范围内的应用的菜单（按钮）树
     * @param iamMenuManagerSelectDto
     * @return list
     */
    @Override
    public List<MenuThreeVo> getMenuThreeInfo(IamMenuManagerSelectDto iamMenuManagerSelectDto) {
        Result<List<MenuThreeVo>> result = iamRoleManagerFeign.getMenuThreeInfo(iamMenuManagerSelectDto);
        if(CollectionUtils.isEmpty(result.getData())){
            throw new RuntimeException("菜单树无数据！");
        }
        return  result.getData();
    }

    /**
     * 功能描述：动、静态用户组权限编辑
     * @param iamStaticUserGroupUsersPermissionEditingDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void staticUserGroupPermissionEdit(IamStaticUserGroupUsersPermissionEditingDto iamStaticUserGroupUsersPermissionEditingDto) {
        //删除按钮旧数据
        iamUserGroupButtonRelationMapper.deleteUserGroupButtonRelation(iamStaticUserGroupUsersPermissionEditingDto);
//        if(0==iamUserGroupButtonRelationMapper.countUserGroupButtonRelation(iamStaticUserGroupUsersPermissionEditingDto)){
//            log.warn("Route==>IamStaticUserGroupManagerServiceImpl method=>staticUserGroupPermissionEdit 用户组权限编辑是，菜单表无旧数据！");
//        }else {
//            int oldCountButton=iamUserGroupButtonRelationMapper.deleteUserGroupButtonRelation(iamStaticUserGroupUsersPermissionEditingDto);
//            if(0==oldCountButton ){
//                throw new RuntimeException("删除按钮旧数据失败！");
//            }
//        }
        //删除菜单旧数据
        iamUserGroupMenuRelationMapper.deleteUserGroupMenuRelation(iamStaticUserGroupUsersPermissionEditingDto);
//        if(0==iamUserGroupMenuRelationMapper.countUserGroupMenuRelation(iamStaticUserGroupUsersPermissionEditingDto)){
//            log.warn("Route==>IamStaticUserGroupManagerServiceImpl method=>staticUserGroupPermissionEdit 用户组权限编辑是，按钮表无旧数据！");
//        }else {
//            int oldCountMenu=iamUserGroupMenuRelationMapper.deleteUserGroupMenuRelation(iamStaticUserGroupUsersPermissionEditingDto);
//            if(0==oldCountMenu ){
//                throw new RuntimeException("删除菜单旧数据失败！");
//            }
//        }
        //先获取勾选的菜单树（可包含按钮）
        iamStaticUserGroupUsersPermissionEditingDto.getMenuThreeVos().forEach((menuThreeVo) ->{
            // 封装菜单或按钮编码
            iamStaticUserGroupUsersPermissionEditingDto.setCode(menuThreeVo.getCode());
            // 按钮
            if(null==menuThreeVo.getMenuLevel()){
                    int buttonRelation = iamUserGroupButtonRelationMapper.insertUserGroupButtonRelation(iamStaticUserGroupUsersPermissionEditingDto);
                    if(0==buttonRelation){
                        throw new RuntimeException("新增按钮数据失败！");
                    }
            }else {
                // 菜单
                int menuRelation = iamUserGroupMenuRelationMapper.insertUserGroupMenuRelation(iamStaticUserGroupUsersPermissionEditingDto);
                if(0==menuRelation){
                    throw new RuntimeException("新增菜单数据失败！");
                }
            }
        });
    }

    /**
     * 功能描述：获取某个静、动态用户组下某个菜单树下已经勾选的菜单或按钮，回填
     * @param iamMenuManagerAlreadySelectDto
     * @return List
     */
    @Override
    public Set<String> getAlreadyMenuThreeInfo(IamMenuManagerAlreadySelectDto iamMenuManagerAlreadySelectDto) {
        List<String> buttons = iamUserGroupButtonRelationMapper.querySelectpButton(iamMenuManagerAlreadySelectDto);
        List<String> menus = iamUserGroupMenuRelationMapper.querySelectMenu(iamMenuManagerAlreadySelectDto);
        Set<String> codes = new TreeSet<>();
        codes.addAll(buttons);
        codes.addAll(menus);
        return codes;
    }


}
